package com.glela.es.util;

import org.elasticsearch.client.Client;
import org.elasticsearch.client.Requests;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.plugin.deletebyquery.DeleteByQueryPlugin;

import java.io.IOException;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsRequest;
import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsResponse;
import org.elasticsearch.action.admin.indices.exists.types.TypesExistsRequest;
import org.elasticsearch.action.admin.indices.exists.types.TypesExistsResponse;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
import org.elasticsearch.action.deletebyquery.DeleteByQueryAction;
import org.elasticsearch.action.deletebyquery.DeleteByQueryRequestBuilder;
import org.elasticsearch.action.deletebyquery.DeleteByQueryResponse;
import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.util.StringUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.glela.common.util.Config;
import com.glela.es.model.BrandForES;
import com.glela.es.model.GoodsForES;

/**
 * ES工具类
 * 
 * @author 卫耀华
 *
 */
public class ESUtil {

	/**
	 * ES服务器的host
	 */
	private static final String host = ESConstant.HOST;

	/**
	 * ES服务器暴露给client的port
	 */
	private static final int port = ESConstant.PORT;

	/**
	 * ES集群名称
	 */
	private static final String clusterName = Config.getString("es.clusterName");

	/**
	 * 获取客户端连接
	 * 
	 * @author 卫耀华
	 * @return
	 * @throws IOException
	 */
	private static Client getClient() throws IOException {
		Settings settings = Settings.settingsBuilder().put("cluster.name", clusterName).build();
		Client client = TransportClient.builder().settings(settings).addPlugin(DeleteByQueryPlugin.class).build()
				.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(host), port));
		return client;
	}

	/**
	 * 判断指定的索引名是否存在
	 * 
	 * @author 卫耀华
	 * @param indexName
	 *            索引名
	 * @return 存在：true; 不存在：false;
	 * @throws IOException
	 */
	public static boolean isExistsIndex(String indexName) throws IOException {
		IndicesExistsResponse response = getClient().admin().indices()
				.exists(new IndicesExistsRequest().indices(new String[] { indexName })).actionGet();
		return response.isExists();
	}

	/**
	 * 判断指定的索引的类型是否存在
	 * 
	 * @author 卫耀华
	 * @param indexName
	 *            索引名
	 * @param indexType
	 *            索引类型
	 * @return 存在：true; 不存在：false;
	 * @throws IOException
	 */
	public static boolean isExistsType(String indexName, String indexType) throws IOException {
		TypesExistsResponse response = getClient().admin().indices()
				.typesExists(new TypesExistsRequest(new String[] { indexName }, indexType)).actionGet();
		return response.isExists();
	}

	/**
	 * 判断一个index中的type是否有数据
	 * 
	 * @author 卫耀华
	 * @param index
	 * @param type
	 * @return
	 * @throws IOException
	 * @throws Exception
	 */
	public static Boolean existDocOfType(String index, String type) throws IOException {
		SearchRequestBuilder builder = getClient().prepareSearch(index).setTypes(type)
				.setSearchType(SearchType.QUERY_THEN_FETCH).setSize(1);
		SearchResponse response = builder.execute().actionGet();
		long docNum = response.getHits().getTotalHits();
		if (docNum == 0) {
			return false;
		}
		return true;
	}

	/**
	 * 根据type来删除数据
	 * 
	 * @author 卫耀华
	 * @param index
	 * @param types
	 * @return
	 * @throws IOException
	 */
	public static long deleteDocByType(String index, String[] types) throws IOException {
		StringBuilder builder = new StringBuilder();
		builder.append("{\"query\":{\"match_all\":{}}}");
		DeleteByQueryResponse response = new DeleteByQueryRequestBuilder(getClient(), DeleteByQueryAction.INSTANCE)
				.setIndices(index).setTypes(types).setSource(builder.toString()).execute().actionGet();
		return response.getTotalDeleted();
	}

	/**
	 * 删除索引
	 * 
	 * @author 卫耀华
	 * @param indices
	 * @throws IOException
	 */
	public static void deleteIndex(String indices) throws IOException {
		DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(indices);
		getClient().admin().indices().delete(deleteIndexRequest);
	}

	/**
	 * 自动创建索引和type
	 * 
	 * @author 卫耀华
	 * @param indexname
	 * @param type
	 * @param list
	 * @throws IOException
	 */
	public static <T> void createIndex(String indexname, String type, List<T> list) throws IOException {
		List<String> jsondata = DataFactory.toJsonData(list);
		// 创建索引库 需要注意的是.setRefresh(true)这里一定要设置,否则第一次建立索引查找不到数据
		IndexRequestBuilder requestBuilder = getClient().prepareIndex(indexname, type).setRefresh(true);
		for (String i : jsondata) {
			Map<String, String> map = JSON.parseObject(i, new TypeReference<Map<String, String>>() {
			});
			String id = map.get("id");
			requestBuilder.setId(id).setSource(i).execute().actionGet();
		}
	}

	/**
	 * 创建索引
	 * 
	 * @author 卫耀华
	 * @param indices
	 * @throws IOException
	 */
	public static void createIndex(String indices) throws IOException {
		getClient().admin().indices().prepareCreate(indices).execute().actionGet();
		getClient().close();
	}

	/**
	 * 创建mapping
	 * 
	 * @author 卫耀华
	 * @param indices
	 * @param mappingType
	 * @throws IOException
	 */
	public static void createGoodsMapping(String indices, String type) throws IOException {
		new XContentFactory();
		XContentBuilder builder = XContentFactory.jsonBuilder().startObject().startObject(indices)
				.startObject("properties").startObject("id").field("type", "long").endObject().startObject("name")
				.field("type", "string").field("analyzer", "ik_smart").endObject().startObject("labelName")
				.field("type", "string").field("analyzer", "ik_smart").endObject().startObject("suggestedPrice")
				.field("type", "long").endObject().startObject("lowestPrice").field("type", "long").endObject()
				.startObject("goodsType").field("type", "string").endObject().startObject("selfSupport")
				.field("type", "long").endObject().endObject().endObject().endObject();
		PutMappingRequest mapping = Requests.putMappingRequest(indices).type(type).source(builder);
		getClient().admin().indices().putMapping(mapping).actionGet();
		getClient().close();
	}

	public static void createBrandMapping(String indices, String type) throws IOException {
		new XContentFactory();
		XContentBuilder builder = XContentFactory.jsonBuilder().startObject().startObject(indices)
				.startObject("properties").startObject("id").field("type", "long").endObject().startObject("nameCn")
				.field("type", "string").field("analyzer", "ik_smart").endObject().startObject("nameEn")
				.field("type", "string").endObject().startObject("logoPath").field("type", "string").endObject()
				.startObject("descriptions").field("type", "string").endObject().startObject("likeCount")
				.field("type", "long").endObject().startObject("status").field("type", "long").endObject().endObject()
				.endObject().endObject();
		PutMappingRequest mapping = Requests.putMappingRequest(indices).type(type).source(builder);
		getClient().admin().indices().putMapping(mapping).actionGet();
		getClient().close();
	}

	/**
	 * 批量更新数据到ES
	 * 
	 * @author 卫耀华
	 * @param indexName
	 * @param typeName
	 * @param newList
	 * @throws IOException
	 */
	public static <T> void bulkUpdate(String indexName, String typeName, List<T> newList) throws IOException {
		if (isExistsIndex(indexName)) {
			if (isExistsType(indexName, typeName)) {
				if (existDocOfType(indexName, typeName)) {
					String[] arr = { typeName };
					deleteDocByType(indexName, arr);
				}
			}
		}
		// 索引不存在，就新建索引
		if (newList != null && newList.size() > 0) {
			createIndex(indexName, typeName, newList);
		}
	}

	public static void syncGoods(String indexName, String typeName, List<GoodsForES> newList) throws IOException {
		if (newList != null && newList.size() > 0) {
			if (isExistsIndex(indexName)) {
				deleteIndex(indexName);
			}
			createIndex(indexName);
			createGoodsMapping(indexName, typeName);
			List<String> jsondata = DataFactory.toJsonData(newList);
			// 创建索引库 需要注意的是.setRefresh(true)这里一定要设置,否则第一次建立索引查找不到数据
			IndexRequestBuilder requestBuilder = getClient().prepareIndex(indexName, typeName).setRefresh(true);
			for (String i : jsondata) {
				Map<String, String> map = JSON.parseObject(i, new TypeReference<Map<String, String>>() {
				});
				String id = map.get("id");
				requestBuilder.setId(id).setSource(i).execute().actionGet();
			}
			getClient().close();
		}
	}

	public static void syncBrand(String indexName, String typeName, List<BrandForES> newList) throws IOException {
		if (newList != null && newList.size() > 0) {
			if (isExistsIndex(indexName)) {
				deleteIndex(indexName);
			}
			createIndex(indexName);
			createBrandMapping(indexName, typeName);
			List<String> jsondata = DataFactory.toJsonData(newList);
			// 创建索引库 需要注意的是.setRefresh(true)这里一定要设置,否则第一次建立索引查找不到数据
			IndexRequestBuilder requestBuilder = getClient().prepareIndex(indexName, typeName).setRefresh(true);
			for (String i : jsondata) {
				Map<String, String> map = JSON.parseObject(i, new TypeReference<Map<String, String>>() {
				});
				String id = map.get("id");
				requestBuilder.setId(id).setSource(i).execute().actionGet();
			}
			getClient().close();
		}
	}

	/**
	 * 搜索商品--分页
	 * 
	 * @author 卫耀华
	 * @param indices
	 * @param type
	 * @param pageStart
	 * @param pageSize
	 * @param searchKeyWord
	 * @return
	 * @throws IOException
	 */
	public static List<String> searchGoods(String indices, String type, int pageStart, int pageSize,
			String searchKeyWord) throws IOException {
		Client client = getClient();
		QueryBuilder queryBuilder = new BoolQueryBuilder().should(QueryBuilders.matchQuery("name", searchKeyWord))
				.should(QueryBuilders.matchQuery("labelName", searchKeyWord));
		SearchRequestBuilder searchRequestBuilder = client.prepareSearch(indices).setTypes(type).setQuery(queryBuilder);
		searchRequestBuilder.setFrom(pageStart);
		searchRequestBuilder.setSize(pageSize);
		searchRequestBuilder.addSort("_score", SortOrder.DESC);
		// searchRequestBuilder.addSort("selfSupport", SortOrder.ASC);
		SearchResponse searchResponse = searchRequestBuilder.execute().actionGet();
		SearchHits hits = searchResponse.getHits();
		SearchHit[] searchHists = hits.getHits();
		List<String> jsonStrList = new ArrayList<String>();
		for (SearchHit hit : searchHists) {
			if (!StringUtils.isEmpty(hit.getSourceAsString())) {
				jsonStrList.add(hit.getSourceAsString());
			}
		}
		client.close();
		return jsonStrList;
	}

	/**
	 * 搜索商品--分页总条数
	 * 
	 * @author 卫耀华
	 * @param indices
	 * @param type
	 * @param searchKeyWord
	 * @return
	 * @throws IOException
	 */
	public static List<String> searchGoodsCount(String indices, String type, String searchKeyWord) throws IOException {
		Client client = getClient();
		QueryBuilder queryBuilder = new BoolQueryBuilder().should(QueryBuilders.matchPhraseQuery("name", searchKeyWord))
				.should(QueryBuilders.matchPhraseQuery("labelName", searchKeyWord));
		SearchRequestBuilder searchRequestBuilder = client.prepareSearch(indices).setTypes(type).setQuery(queryBuilder);
		searchRequestBuilder.setFrom(0);
		searchRequestBuilder.setSize(5000);
		SearchResponse searchResponse = searchRequestBuilder.execute().actionGet();
		SearchHits hits = searchResponse.getHits();
		SearchHit[] searchHists = hits.getHits();
		List<String> jsonStrList = new ArrayList<String>();
		for (SearchHit hit : searchHists) {
			if (!StringUtils.isEmpty(hit.getSourceAsString())) {
				jsonStrList.add(hit.getSourceAsString());
			}
		}
		client.close();
		return jsonStrList;
	}

	/**
	 * 搜索品牌
	 * 
	 * @author 卫耀华
	 * @param indices
	 * @param type
	 * @param searchKeyWord
	 * @return
	 * @throws IOException
	 */
	public static List<String> searchBrand(String indices, String type, String searchKeyWord, int pageStart,
			int pageSize) throws IOException {
		Client client = getClient();
		QueryBuilder queryBuilder = new BoolQueryBuilder()
				.must(QueryBuilders.matchPhraseQuery("nameCn", searchKeyWord));
		SearchRequestBuilder searchRequestBuilder = client.prepareSearch(indices).setTypes(type).setQuery(queryBuilder);
		searchRequestBuilder.setFrom(pageStart);
		searchRequestBuilder.setSize(pageSize);
		SearchResponse searchResponse = searchRequestBuilder.execute().actionGet();
		SearchHits hits = searchResponse.getHits();
		SearchHit[] searchHists = hits.getHits();
		List<String> jsonStrList = new ArrayList<String>();
		for (SearchHit hit : searchHists) {
			if (!StringUtils.isEmpty(hit.getSourceAsString())) {
				jsonStrList.add(hit.getSourceAsString());
			}
		}
		client.close();
		return jsonStrList;
	}

}
